package com.study.androidsystem.anno_reflec.injectListener;

import android.app.Activity;
import android.view.View;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <pre>
 *     author : slx
 *     time   : 2020/12/02
 *     desc   :
 * </pre>
 */
public class InjectListenerUtil {
    public static void injectEvent(Activity activity) {
        Class<? extends Activity> aClass = activity.getClass();
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            Annotation[] annotations = declaredMethod.getAnnotations();
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> annotationType = annotation.annotationType();
                if (annotationType.isAnnotationPresent(EventType.class)) {
                    // 找到EventType注解,注解的注解
                    EventType eventTypeAnno = annotationType.getAnnotation(EventType.class);
                    String listenerSetter = eventTypeAnno.listenerSetter();
                    Class listenerType = eventTypeAnno.listenerType();
                    try {
                        // 获取注解的value方法
                        Method valueMethod = annotationType.getDeclaredMethod("value");
                        // 获取注解中所有view的id
                        int viewIds[] = (int[]) valueMethod.invoke(annotation);
                        declaredMethod.setAccessible(true);

                        // 创建代理
                        Object o = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[]{listenerType},
                                new ListenerInvocationHandler<>(declaredMethod, activity));

                        for (int viewId : viewIds) {
                            View injectView = activity.findViewById(viewId);
                            Method method = injectView.getClass().getMethod(listenerSetter, listenerType);
                            method.invoke(injectView, o);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    static class ListenerInvocationHandler<T> implements InvocationHandler {

        private Method method;
        private T target;

        public ListenerInvocationHandler(Method method, T target) {
            this.method = method;
            this.target = target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return this.method.invoke(target, args);
        }
    }
}